/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.haoxuer.discover.chain.impl;


import com.haoxuer.discover.chain.Chain;
import com.haoxuer.discover.chain.Command;
import org.apache.commons.chain2.Processing;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class ChainBase<Request,Response> implements Chain<Request,Response>  {

    public ChainBase() {
    }

    public ChainBase(Command command) {
        addCommand(command);
    }

    public ChainBase(Command... commands) {
        if (commands == null) {
            throw new IllegalArgumentException();
        }
        for (Command command : commands) {
            addCommand(command);
        }
    }

    public ChainBase(Collection<Command> commands) {
        if (commands == null) {
            throw new IllegalArgumentException();
        }
        for (Command command : commands) {
            addCommand( command );
        }
    }

    // ----------------------------------------------------- Instance Variables

    /**
     * <p>The list of {@link Command}s configured for this {@link Chain}, in
     * the order in which they may delegate processing to the remainder of
     * the {@link Chain}.</p>
     */
    private final List<Command> commands = new ArrayList<>();

    /**
     * <p>Flag indicating whether the configuration of our commands list
     * has been frozen by a call to the <code>execute()</code> method.</p>
     */
    private boolean frozen = false;

    // ---------------------------------------------------------- Chain Methods

    public  void addCommand(Command command) {
        if (command == null) {
            throw new IllegalArgumentException();
        }
        if (frozen) {
            throw new IllegalStateException();
        }
        commands.add( command );
    }


    public Processing execute(Request request,Response response) {
        // Verify our parameters
        if (request == null) {
            throw new IllegalArgumentException("Can't execute a null context");
        }
        frozen = true;

        Processing saveResult = Processing.CONTINUE;
        int i = 0;
        int n = commands.size();
        Command lastCommand = null;
        for (i = 0; i < n; i++) {
                lastCommand = commands.get(i);
                saveResult = lastCommand.execute(request,response);
                if(saveResult == null) {
                    break;
                } else if (saveResult != Processing.CONTINUE) {
                    break;
                }
        }
        return saveResult;
    }


    /**
     * Returns true, if the configuration of our commands list
     * has been frozen by a call to the <code>execute()</code> method,
     * false otherwise.
     *
     * @return true, if the configuration of our commands list
     * has been frozen by a call to the <code>execute()</code> method,
     * false otherwise.
     * @since 2.0
     */
    public boolean isFrozen() {
        return frozen;
    }

    // -------------------------------------------------------- Package Methods

    /**
     * <p>Return an array of the configured {@link Command}s for this
     * {@link Chain}.  This method is package private, and is used only
     * for the unit tests.</p>
     */
    List<Command> getCommands() {
        return commands;
    }

}
